using System;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;
using System.Diagnostics;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace RunAllTestsInSolutionTask
{
    internal class SolutionParser
    {
        private static string _SolutionPath;

        public static IList<string> GetAllDlls(string solutionFile, string configuration)
        {
            var projectFileNames = GetAllProjectsFromSolution(solutionFile);
            var dllFiles = GetDllsFromProjectFiles(projectFileNames, configuration);
            return dllFiles;
        }

        public static IList<string> GetAllTestDlls(string slnfileName, string configuration)
        {
            var projectFileNames = GetAllProjectsFromSolution(slnfileName);
            var dllFiles = GetTestdllsFromProjectFiles(projectFileNames, configuration);
            return dllFiles;
        }

        public static IList<string> GetAllTestDlls(string slnFileName, string configuration, string excludedList)
        {
            var projectFileNames = GetAllProjectsFromSolution(slnFileName);
            var afterExclude = (from project in projectFileNames
                                where !(project.Contains(excludedList))
                                select project).ToList();
            var dllFiles = GetTestdllsFromProjectFiles(afterExclude, configuration);
            return dllFiles;
        }

        private static IList<string> GetAllProjectsFromSolution(string solutionFile)
        {
            if (!File.Exists(solutionFile))
                throw new ArgumentException("Sln File Not Found:" + solutionFile);
            _SolutionPath = Path.GetDirectoryName(solutionFile);
            var solutionXml = Load(solutionFile);
            var projectFileNames = GetAllProjectsFiles(solutionXml);
            return projectFileNames;
        }


        private static IList<string> GetAllProjectsFiles(IList<string> lines)
        {
            IList<string> result = new List<string>();

            var ans = from line in lines
                      where (line.StartsWith("Project("))
                      select line;

            foreach (var line in ans)
            {
                var dll = GetProjectFileFromLine(line);
                dll = Path.Combine(_SolutionPath, dll.Trim().Trim('"'));
                result.Add(dll);
            }

            result = (from projFile in result
                      where ((projFile.EndsWith(".csproj")) || (projFile.EndsWith(".vcxproj")))
                      select projFile).ToList();

            return result;
        }

        private static string GetProjectFileFromLine(string line)
        {
            var parts = line.Split(new char[] { ',' });
            return parts[1];
        }

        private static IList<string> Load(string slnfileName)
        {
            var lines = new List<string>();
            StreamReader file = new StreamReader(slnfileName);
            while (!file.EndOfStream)
            {
                var line = file.ReadLine();
                lines.Add(line);
            }
            return lines;
        }

        private static IList<string> GetTestdllsFromProjectFiles(IList<String> projectFileNames, string configuration)
        {
            var result = new List<string>();
            foreach (String projectFileName in projectFileNames)
            {
                try
                {
                    IProjectParser parser;
                    if (CSharpProject(projectFileName))
                        parser = new CSharpProjectParser(projectFileName);
                    else
                        parser = new ManagedProjectParser(projectFileName);

                    if (parser.IsTestProject())
                        result.Add(parser.GetOutputFile(configuration));
                }
                catch
                {
                    Console.WriteLine(String.Format("Failed to Parse Project: {0}, {1}", projectFileName, configuration));
                    throw;
                }
            }
            return result;
        }

        private static IList<string> GetDllsFromProjectFiles(IList<String> projectFileNames, string configuration)
        {
            var result = new List<string>();
            foreach (String projectFileName in projectFileNames)
            {
                try
                {
                    IProjectParser parser;
                    if (CSharpProject(projectFileName))
                        parser = new CSharpProjectParser(projectFileName);
                    else
                        parser = new ManagedProjectParser(projectFileName);

                    result.Add(parser.GetOutputFile( configuration));
                }
                catch
                {
                    Console.WriteLine(String.Format("Failed to Parse Project: {0}, {1}", projectFileName, configuration));
                    throw;
                }
            }
            return result;
        }
        private static bool CSharpProject(string projectFileName)
        {
            return projectFileName.EndsWith(".csproj");
        }

    }
}
